#ifndef __KITSCH_EXCEPTION_H__
#define __KITSCH_EXCEPTION_H__

#include <exception>

namespace Kitsch {
	namespace Exception {
		class KitschException : public std::exception
		{
		public:
			explicit KitschException(std::string file, int line, std::string msg) 
				: _file(file), _line(line), _msg(msg) {}

			explicit KitschException(const KitschException &k)
				: _file(k._file), _line(k._line), _msg(k._msg) {}

			virtual const char* what() const throw() {
				std::ostringstream buf;
				buf << _file << "(" << _line << "): " << _msg;
				return buf.str().c_str();
			}

		private:
			std::string _msg;
			std::string _file;
			int _line;
		};

		class KitschRuntimeException : public std::runtime_error
		{
		public:
			explicit KitschException(std::string file, int line, std::string msg) 
				: _file(file), _line(line), _msg(msg) {}
			explicit KitschException(const KitschException &k)
				: _file(k._file), _line(k._line), _msg(k._msg) {}
			virtual ~KitschRuntimeException() {}

			virtual const char* what() const throw() {
				std::ostringstream buf;
				buf << _file << "(" << _line << "): " << _msg;
				return buf.str().c_str();
			}

		private:
			std::string _msg;
			std::string _file;
			int _line;
		};

		class KitschUnknownException : public std::bad_exception
		{
		public:
			explicit KitschUnknownException(std::string file,
							int line,
							std::string msg) 
				: _file(file), _line(line), _msg(msg) {}
			explicit KitschUnknownException(const KitschUnkownException &k)
				: _file(k._file), _line(k._line), _msg(k._msg) {}
			virtual ~KitschUnknownException() {}

			virtual const char* what() const throw() {
				std::ostringstream buf;
				buf << _file << "(" << _line << "): " << _msg;
				return buf.str().c_str();
			}

		private:
			std::string _msg;
			std::string _file;
			int _line;
		};

		class KitschAllocationException : public std::bad_alloc
		{
		public:
			explicit KitschAllocationException(std::string file,
							   int line,
							   std::string msg) 
				: _file(file), _line(line), _msg(msg) {}
			explicit KitschAllocationException(const KitschAllocationException &k)
				: _file(k._file), _line(k._line), _msg(k._msg) {}
			virtual ~KitschAllocationException() {}

			virtual const char* what() const throw() {
				std::ostringstream buf;
				buf << _file << "(" << _line << "): " << _msg;
				return buf.str().c_str();
			}

		private:
			std::string _msg;
			std::string _file;
			int _line;
		};

		class KitschIOException : public std::ios_base::failure
		{
		public:
			explicit KitschIOException(std::string file, int line, std::string msg) 
				: _file(file), _line(line), _msg(msg) {}
			explicit KitschIOException(const KitschException &k)
				: _file(k._file), _line(k._line), _msg(k._msg) {}
			virtual ~KitschIOException() {}

			virtual const char* what() const throw() {
				std::ostringstream buf;
				buf << _file << "(" << _line << "): " << _msg;
				return buf.str().c_str();
			}

		private:
			std::string _msg;
			std::string _file;
			int _line;
		};

		class KitschCastException : public std::ios_base::failure
		{
		public:
			explicit KitschCastException(std::string file, int line, std::string msg) 
				: _file(file), _line(line), _msg(msg) {}
			explicit KitschCastException(const KitschCastException &k)
				: _file(k._file), _line(k._line), _msg(k._msg) {}
			virtual ~KitschCastException() {}

			virtual const char* what() const throw() {
				std::ostringstream buf;
				buf << _file << "(" << _line << "): " << _msg;
				return buf.str().c_str();
			}

		private:
			std::string _msg;
			std::string _file;
			int _line;
		};
	}
}

#define MAKE_EXCEPTION(exception, message)
throw Kitch::Exception::KitschException(__FILE__, __LINE__, message);

#endif /* __KITSCH_EXCEPTION_H__ */

